HAL MMC typical use cases for migration

This section provides information about the HAL MMC Typical use cases for migration.

Note

The typical read and write operations—whether using polling, DMA, or interrupt (IT) modes—remain largely unchanged for the user between HAL1 and HAL2. The main difference in HAL2 is a refactored callback registration and handling model: transfer completion callbacks are now unified and event-driven, simplifying application code.

RPMB (Replay Protected Memory Block) operations also follow the same use cases as before, with only minor naming changes to APIs and parameters.

The most significant changes in HAL2 are in the linked-list DMA management. Linked-list operations now use a generic HAL Q API for node and queue management.

HAL Q is a new HAL layer introduced in HAL2 that provides advanced linked-list features shared across multiple HAL drivers. It centralizes linked-list management, improving code reuse and maintainability.

Card removal/insertion handling differs from HAL1 to HAL2:

  • With HAL1, in the event of card plug-in/plug-off, user should call HAL_MMC_InitCard() upon the card insertion.

  • With HAL2 the application calls HAL_MMC_NotifyCardRemoval() on removal to reset the peripheral to default configuration and HAL_MMC_NotifyCardInsertion() on insertion to initialize the card and apply user configuration.

Use case: HAL MMC polling transfer mode

Sequence diagram

This transfer sequence in polling mode remains unchanged between HAL1 and HAL2.

@startuml
hide footbox
participant "User Application" as part1
participant "HAL MMC" as part2
activate part1
activate part2
group I/O Operation process
part1->part2 : HAL_MMC_Erase()
part2 --> part1: HAL Status
part1->part1 : Wait for HAL_MMC_GetCardState() == HAL_MMC_CARD_TRANSFER
part1->part2 : HAL_MMC_WriteBlocks()
part2 --> part1: HAL Status
part1->part1 : Wait for HAL_MMC_GetCardState() == HAL_MMC_CARD_TRANSFER
part1->part2 : HAL_MMC_ReadBlocks()
part2 --> part1: HAL Status
part1->part1 : Wait for HAL_MMC_GetCardState() == HAL_MMC_CARD_TRANSFER
end
@enduml

Code Snippet

uint8_t Buffer_Block_Tx[BufferWordsSize], Buffer_Block_Rx[BufferWordsSize];
/* Write one block then read back (polling) */

MMC_state = HAL_MMC_Erase(&hmmc_card, BlockStartAdd, BlockEndAdd);
/* Wait for the Card Transfer status */
while(HAL_MMC_GetCardState(&hmmc_card) != HAL_MMC_CARD_TRANSFER)
{}

if (MMC_state == HAL_OK)
{
   /* Write NumberOfBlocks blocks of BufferWordsSize bytes on address BlockAddress */
   MMC_state = HAL_MMC_WriteBlocks(&hmmc_card, Buffer_Block_Tx, BlockAddress, NumberOfBlocks, UserTimeout_ms);
}
else
{
   Error_Handler();
}

/* Wait for the Card Transfer status before starting a read operation */
while(HAL_MMC_GetCardState(&hmmc_card) != HAL_MMC_CARD_TRANSFER)
{}

if (MMC_state == HAL_OK)
{
   /* Read NumberOfBlocks blocks of BufferWordsSize bytes from address BlockAddress */
   MMC_state = HAL_MMC_ReadBlocks(&hmmc_card, Buffer_Block_Rx, BlockAddress, NumberOfBlocks, UserTimeout_ms);
}
else
{
   Error_Handler();
}

/* Wait for the Card Transfer status */
while(HAL_MMC_GetCardState(&hmmc_card) != HAL_MMC_CARD_TRANSFER)
{}

Use case: HAL MMC IT transfer mode

Sequence diagram

HAL1

HAL2

IT transfer mode uses HAL_MMC_WriteBlocks_IT and HAL_MMC_ReadBlocks_IT for non-blocking operations. Transfer complete is signaled via callback functions (registered with HAL_MMC_RegisterCallback for TX and RX complete separately).

IT transfer sequence remains mostly unchanged between HAL1 and HAL2, but callback registration is unified via HAL_MMC_RegisterXferCpltCallback registering a single callback that handles both TX and RX events through an event parameter.

@startuml
hide footbox
participant "User Application" as part1
participant "HAL MMC" as part2
participant "NVIC" as part3
activate part1
activate part2

group Register transfer complete callbacks
part1->part2 : HAL_MMC_RegisterCallback(&hmmc_card, HAL_MMC_TX_CPLT_CB_ID, TxCpltCallback)
part2 --> part1
part1->part2 : HAL_MMC_RegisterCallback(&hmmc_card, HAL_MMC_RX_CPLT_CB_ID, RxCpltCallback)
part2 --> part1
end

group I/O Operation process
part1->part2 : HAL_MMC_WriteBlocks_IT()
part2-->part1 : HAL Status
part3 -> part2 : HAL_MMC_IRQ_HANDLER()
part2 -> part1 : Notify the User application with Transmission complete
part1->part1 : Wait for HAL_MMC_GetCardState() == HAL_MMC_CARD_TRANSFER
part1->part2 : HAL_MMC_ReadBlocks_IT()
part2-->part1 : HAL Status
part3 -> part2 : HAL_MMC_IRQ_HANDLER()
part2 -> part1 : Notify the User application with Reception complete
part1->part1 : Wait for HAL_MMC_GetCardState() == HAL_MMC_CARD_TRANSFER
end
@enduml

Code Snippet

HAL1

HAL2

uint8_t Buffer_Block_Tx[BufferWordsSize];
uint8_t Buffer_Block_Rx[BufferWordsSize];

/* Register the Tx and Rx
   Transfer complete callbacks */
HAL_MMC_RegisterCallback(&hmmc_card,
                         HAL_MMC_TX_CPLT_CB_ID,
                         TxCpltCallback);
HAL_MMC_RegisterCallback(&hmmc_card,
                         HAL_MMC_RX_CPLT_CB_ID,
                         RxCpltCallback);

/* Write NumberOfBlocks blocks of BufferWordsSize
   bytes on address BlockAddress */
MMC_state = HAL_MMC_WriteBlocks_IT(&hmmc_card,
                                   Buffer_Block_Tx,
                                   BlockAddress,
                                   NumberOfBlocks);
/* Wait for the Writing process is completed */
while(mmctransfertx == 0)
{}

/* Wait for the Card Transfer status before
   starting a read operation */
while(HAL_MMC_GetCardState(&hmmc_card)
      != HAL_MMC_CARD_TRANSFER)
{}

if (MMC_state == HAL_OK)
{
   /* Read NumberOfBlocks blocks of BufferWordsSize
      bytes from address BlockAddress */
   MMC_state = HAL_MMC_ReadBlocks_IT(&hmmc_card,
                                     Buffer_Block_Rx,
                                     BlockAddress,
                                     NumberOfBlocks);
}
else
{
   Error_Handler();
}
/* Wait for the Reading process is completed */
while(mmctransferrx == 0)
{}
/* Wait for the Card Transfer status before
   proceeding with another MMC operation */
while(HAL_MMC_GetCardState(&hmmc_card)
      != HAL_MMC_CARD_TRANSFER)
{}

void TxCpltCallback(MMC_HandleTypeDef *hmmc) {
   mmctransfertx = 1;
}

void RxCpltCallback(MMC_HandleTypeDef *hmmc) {
   mmctransferrx = 1;
}
 uint8_t Buffer_Block_Tx[BufferWordsSize];
 uint8_t Buffer_Block_Rx[BufferWordsSize];

 /* Register the Tx and Rx Transfer complete callbacks */
 HAL_MMC_RegisterXferCpltCallback(&hmmc, MyMmcXferCallback);







 /* Write NumberOfBlocks blocks of
    BufferWordsSize bytes on address BlockAddress */
 MMC_state = HAL_MMC_WriteBlocks_IT(&hmmc_card,
                                    Buffer_Block_Tx,
                                    BlockAddress,
                                    NumberOfBlocks);
 /* Wait for the Writing process is completed */
 while(mmctransfertx == 0)
 {}

 /* Wait for the Card Transfer status
    before starting a read operation */
 while(HAL_MMC_GetCardState(&hmmc_card)
       != HAL_MMC_CARD_TRANSFER)
 {}

 if (MMC_state == HAL_OK)
 {
    /* Read NumberOfBlocks blocks of
       BufferWordsSize bytes from address BlockAddress */
    MMC_state = HAL_MMC_ReadBlocks_IT(&hmmc_card,
                                      Buffer_Block_Rx,
                                      BlockAddress,
                                      NumberOfBlocks);
 }
 else
 {
    Error_Handler();
 }
 /* Wait for the Reading process is completed */
 while(mmctransferrx == 0)
 {}
 /* Wait for the Card Transfer status
 before proceeding with another MMC operation */
 while(HAL_MMC_GetCardState(&hmmc_card)
       != HAL_MMC_CARD_TRANSFER)
 {}

 void MyMmcXferCallback(hal_mmc_handle_t *hmmc,
                        hal_mmc_event_cb_t cb_event) {
    switch (cb_event) {
       case HAL_MMC_EVENT_CB_TX_CPLT:
       mmctransferrx = 1;
       break;
       case HAL_MMC_EVENT_CB_RX_CPLT:
       mmctransferrx = 1;
       break;
       default: break;
     }
}

Use case: HAL MMC DMA transfer mode

Sequence diagram

HAL1

HAL2

DMA transfer mode uses HAL_MMC_WriteBlocks_DMA and HAL_MMC_ReadBlocks_DMA for non-blocking operations. Transfer complete is signaled via callback functions (registered with HAL_MMC_RegisterCallback for TX and RX complete separately).

DMA transfer sequence remains mostly unchanged between HAL1 and HAL2, but callback registration is unified via HAL_MMC_RegisterXferCpltCallback registering a single callback that handles both TX and RX events through an event parameter.

@startuml
hide footbox
participant "User Application" as part1
participant "HAL MMC" as part2
participant "NVIC" as part3
activate part1
activate part2
group I/O Operation process
part1->part2 : HAL_MMC_WriteBlocks_DMA()
part2-->part1 : HAL Status
part3 -> part2 : HAL_MMC_IRQ_HANDLER()
part2 -> part1 : Notify the User application with Transmission complete
part1->part1 : Wait for HAL_MMC_GetCardState() == HAL_MMC_CARD_TRANSFER
part1->part2 : HAL_MMC_ReadBlocks_DMA()
part2-->part1 : HAL Status
part3 -> part2 : HAL_MMC_IRQ_HANDLER()
part2 -> part1 : Notify the User application with Reception complete
part1->part1 : Wait for HAL_MMC_GetCardState() == HAL_MMC_CARD_TRANSFER
end
@enduml

Code Snippet

uint8_t Buffer_Block_Tx[BufferWordsSize], Buffer_Block_Rx[BufferWordsSize];
/* Write NumberOfBlocks blocks of BufferWordsSize bytes on address BlockAddress */
MMC_state = HAL_MMC_WriteBlocks_DMA(&hmmc_card, Buffer_Block_Tx, BlockAddress, NumberOfBlocks);
  /* Wait for the Writing process is completed */
while(mmctransfertx == 0) /* The variable ``mmctransfertx`` is updated by
                             the callback function */
{}

/* Wait for the Card Transfer status before starting a read operation */
while(HAL_MMC_GetCardState(&hmmc_card) != HAL_MMC_CARD_TRANSFER)
{}

if (MMC_state == HAL_OK)
{
   /* Read NumberOfBlocks blocks of BufferWordsSize bytes from address BlockAddress */
   MMC_state = HAL_MMC_ReadBlocks_DMA(&hmmc_card, Buffer_Block_Rx, BlockAddress, NumberOfBlocks);
}
else
{
   Error_Handler();
}
/* Wait for the Reading process is completed */
while(mmctransferrx == 0) /* The variable ``mmctransferrx`` is updated by
                             the callback function  */
{}
/* Wait for the Card Transfer status before proceeding with another MMC operation */
while(HAL_MMC_GetCardState(&hmmc_card) != HAL_MMC_CARD_TRANSFER)
{}

Use case: HAL MMC Card RPMB management

Sequence diagram

RPMB operations remain largely unchanged between HAL1 and HAL2 except for renaming of APIs and parameters.

@startuml
hide footbox
participant "User Application" as part1
participant "HAL MMC" as part2

activate part1
activate part2

group Replay Protected Memory Block management

part1->part2 : HAL_MMC_SwitchPartition()
part2 --> part1

group Program Authentication key
part1->part2 : HAL_MMC_RPMB_ProgramAuthenticationKey()
note right: One-time programmable; cannot be reprogrammed.
part2 --> part1
end

part1->part2 : HAL_MMC_RPMB_GetWriteCounter()
part2 --> part1

part1 -> part1: Generate the MAC for the data to be written. \n The user can use the HAL HASH driver.

part1->part2 : HAL_MMC_RPMB_WriteBlocks()
part2 --> part1

part1->part2 : HAL_MMC_RPMB_ReadBlocks()
part2 --> part1

part1->part2 : HAL_MMC_GetRPMBError()
part2 --> part1

end
@enduml

Code Snippet

HAL1

HAL2

if (HAL_MMC_SwitchPartition(&hmmc_card,
                            HAL_MMC_RPMB_PARTITION)
    != HAL_OK)
{
  Error_Handler();
}

#if defined (RPMB_KEY_IS_NOT_YET_PROGRAMMED)
    && (RPMB_KEY_IS_NOT_YET_PROGRAMMED == 1U)
if (HAL_MMC_RPMB_ProgramAuthenticationKey(&hmmc_card,
                                          pKey,
                                          1000)
    != HAL_OK)
{
  Error_Handler();
}
#endif /* RPMB_KEY_IS_NOT_YET_PROGRAMMED */

/*----------------- Get Write Counter ------------------*/
write_counter = HAL_MMC_RPMB_GetWriteCounter(&hmmc_card,
                                             nonce_buffer,
                                             1000);


/*-------------------- Generate MAC --------------------*/

/* Initialize and Init the HAL HASH Driver */
/* Compute SHA-256 digest by using the HAL HASH driver */
.
..
...

/* Wait for the Card Transfer status */
while(HAL_MMC_GetCardState(&hmmc_card)
      != HAL_MMC_CARD_TRANSFER)
{}

/*-------------- Write Authenticated data -------------*/
if (HAL_MMC_RPMB_WriteBlocks(&hmmc_card,
                             Buffer_tx_data,
                             blockadd,
                             numberofblocks,
                             mac,
                             5000U)
    != HAL_OK)
{
  Error_Handler();
}

/*------------- Read Authenticated data ---------------*/
if (HAL_MMC_RPMB_ReadBlocks(&hmmc_card,
                            Buffer_rx_data,
                            blockadd,
                            numberofblocks,
                            nonce_buffer,
                            mac,
                            0xFFFFFFFFU)
    != HAL_OK)
{
  Error_Handler();
}

/* Check the RPMB error code */
if (HAL_MMC_GetRPMBError(&hmmc_card)
    != HAL_MMC_ERROR_RPMB_OPERATION_OK)
{
  Error_Handler();
}
if (HAL_MMC_SelectPartitionArea(&hmmc_card,
                                HAL_MMC_AREA_PARTITION_RPMB)
    != HAL_OK)
{
  Error_Handler();
}

#if defined (RPMB_KEY_IS_NOT_YET_PROGRAMMED)
    && (RPMB_KEY_IS_NOT_YET_PROGRAMMED == 1U)
if (HAL_MMC_ProgramRPMBAuthenticationKey(&hmmc_card,
                                         pKey,
                                         1000)
    != HAL_OK)
{
  Error_Handler();
}
#endif /* RPMB_KEY_IS_NOT_YET_PROGRAMMED */

/*--------------- Get Write Counter ----------------*/
(void)HAL_MMC_GetRPMBWriteCounter(&hmmc_card,
                                nonce_buffer,
                                &write_counter,
                                1000);

/*------------------ Generate MAC ------------------*/

/* Initialize and Init the HAL HASH Driver */
/* Compute SHA-256 digest by using the HAL HASH driver */
.
..
...

/* Wait for the Card Transfer status */
while(HAL_MMC_GetCardState(&hmmc_card)
      != HAL_MMC_CARD_TRANSFER)
{}

/*--------------- Write Authenticated data ------------*/
if (HAL_MMC_WriteRPMBBlocks(&hmmc_card,
                            Buffer_tx_data,
                            blockadd,
                            numberofblocks,
                            mac,
                            5000U)
    != HAL_OK)
{
  Error_Handler();
}

/*---------------- Read Authenticated data -------------*/
if (HAL_MMC_ReadRPMBBlocks(&hmmc_card,
                           Buffer_rx_data,
                           blockadd,
                           numberofblocks,
                           nonce_buffer,
                           mac,
                           0xFFFFFFFFU)
    != HAL_OK)
{
  Error_Handler();
}

/* Check the RPMB error code */
if (HAL_MMC_GetRPMBErrorCodes(&hmmc_card)
    != HAL_MMC_RPMB_OPERATION_OK)
{
  Error_Handler();
}

Use case: HAL MMC linked-list DMA transfer

Sequence diagram

HAL1

HAL2

Linked-list DMA transfer mode uses linked list node building and insertion APIs ( HAL_MMCEx_DMALinkedList_BuildNode(), HAL_MMCEx_DMALinkedList_InsertNode()) to create a queue of DMA transfer nodes. The user initiates write and read operations using linked-list specific functions ( HAL_MMCEx_DMALinkedList_WriteBlocks(), HAL_MMCEx_DMALinkedList_ReadBlocks()).

In HAL2 linked-list DMA transfer is updated with most of linked-list management handled by HAL Q driver (A new driver provided with HAL2). The user builds nodes using HAL_MMC_FillNodeConfig(), initializes the queue with HAL_Q_Init(), and inserts nodes using HAL_Q_InsertNode(). The I/O operations are performed with HAL_MMC_WriteBlocks_LinkedList() and HAL_MMC_ReadBlocks_LinkedList(). Refer to linked-list management I/O operations and HAL Q documentation for more details.

@startuml
hide footbox
participant "User Application" as part1
participant "HAL MMC" as part2
participant "NVIC" as part3

activate part1
activate part2

group Linked List Building
  part1->part2 : HAL_MMCEx_DMALinkedList_BuildNode(&MMC_Nx, &MMC_Node_Conf)
  note right : Build node MMC_Nx from MMC_Node_Conf filled by user. \nRepeat for each node to be configured.
  part1->part2 : HAL_MMCEx_DMALinkedList_InsertNode(&Q1, <previous_node>, &MMC_Nx)
  note right : Insert each node into the queue as needed. \nRepeat for all nodes to be linked.
end

group I/O Operation process
part1->part2 : HAL_MMC_Erase()
part2 --> part1: Erase completed

part1->part2 : HAL_MMCEx_DMALinkedList_WriteBlocks()
part2-->part1

part3 -> part2 : HAL_MMC_IRQ_HANDLER()
part2 -> part1 : Notify TX complete
part1->part1 : Wait HAL_MMC_GetCardState() == HAL_MMC_CARD_TRANSFER

part1->part2 : HAL_MMCEx_DMALinkedList_ReadBlocks()
part3 -> part2 : HAL_MMC_IRQ_HANDLER()
part2 -> part1 : Notify RX complete
part1->part1 : Wait HAL_MMC_GetCardState() == HAL_MMC_CARD_TRANSFER
end
@enduml

Code Snippet

HAL1

HAL2

/****************************************************** Build SDMMC node 1 */
 MMC_Node_Conf.BufferAddress = (uint32_t) &(Buffer_Tx[0]);
 MMC_Node_Conf.BufferSize = BLOCKSIZE*1;
 HAL_MMCEx_DMALinkedList_BuildNode(&MMC_N1, &MMC_Node_Conf);
/************************************************************ Build node 2 */
 MMC_Node_Conf.BufferAddress = (uint32_t) &(Buffer_Tx[BufferWordsSize]);
 MMC_Node_Conf.BufferSize = BLOCKSIZE*2;
 HAL_MMCEx_DMALinkedList_BuildNode(&MMC_N2, &MMC_Node_Conf);
/************************************************************ Build node 3 */
 MMC_Node_Conf.BufferAddress = (uint32_t) &(Buffer_Tx[BufferWordsSize*3]);
 MMC_Node_Conf.BufferSize = BLOCKSIZE*3;
 HAL_MMCEx_DMALinkedList_BuildNode(&MMC_N3, &MMC_Node_Conf);

/* Define list object */
 MMC_DMALinkedListTypeDef Q_write;


/*********************************************** Connect node 1 to Queue 1 */
 HAL_MMCEx_DMALinkedList_InsertNode(&Q_write, NULL, &MMC_N1);
/*********************************************** Connect node 2 to Queue 1 */
 HAL_MMCEx_DMALinkedList_InsertNode(&Q_write, &MMC_N1, &MMC_N2);
/*********************************************** Connect node 3 to Queue 1 */
 HAL_MMCEx_DMALinkedList_InsertNode(&Q_write, &MMC_N2, &MMC_N3);

/*  Write steps */
 /* Write blocks using DMA transfer with linked list */
 if (HAL_MMCEx_DMALinkedList_WriteBlocks(&hmmc_card, &Q_write, 1000, 12) != HAL_OK)
 {
   Error_Handler();
 }

 /*************************************************** Wait for TX complete */
 while (mmctransfertx == 0)
 {}
 /******************************************* Wait for card transfer state */
 while (HAL_MMC_GetCardState(&hmmc_card) != HAL_MMC_CARD_TRANSFER)
 {}


/* Read steps */
 MMC_Node_Conf.BufferAddress = (uint32_t) &(Buffer_Rx[0]);
 MMC_Node_Conf.BufferSize = BLOCKSIZE;
 HAL_MMCEx_DMALinkedList_BuildNode(&MMC_N4, &MMC_Node_Conf);

 MMC_Node_Conf.BufferAddress = (uint32_t) &(Buffer_Rx[BufferWordsSize*2]);
 MMC_Node_Conf.BufferSize = BLOCKSIZE*2;
 HAL_MMCEx_DMALinkedList_BuildNode(&MMC_N5, &MMC_Node_Conf);

 MMC_Node_Conf.BufferAddress = (uint32_t) &(Buffer_Rx[BufferWordsSize*3]);
 MMC_Node_Conf.BufferSize = BLOCKSIZE*3;
 HAL_MMCEx_DMALinkedList_BuildNode(&MMC_N6, &MMC_Node_Conf);

 /* Define list object */
 MMC_DMALinkedListTypeDef Q_read;


 HAL_MMCEx_DMALinkedList_InsertNode(&Q_read, NULL, &MMC_N4);
 HAL_MMCEx_DMALinkedList_InsertNode(&Q_read, &MMC_N4, &MMC_N5);
 HAL_MMCEx_DMALinkedList_InsertNode(&Q_read, &MMC_N5, &MMC_N6);

 /* Read back written block using DMA linked-list transfer */
 if (HAL_MMCEx_DMALinkedList_ReadBlocks(&hmmc_card, &Q_read, 1000,12) != HAL_OK)
 {
   Error_Handler();
 }
 /*********************************************** Wait for RX/TX complete */
 while (mmctransferrx == 0)
 {}
 /****************************************** Wait for card transfer state */
 while (HAL_MMC_GetCardState(&hmmc_card) != HAL_MMC_CARD_TRANSFER)
 {}
/**************************************************** Build SDMMC node 1 */


HAL_MMC_FillNodeConfig(&MMC_N1, &(Buffer_Tx[0]), 1 * BLOCKSIZE);
/********************************************************** Build node 2 */


HAL_MMC_FillNodeConfig(&MMC_N2, &(Buffer_Tx[BufferWordsSize]), 2 * BLOCKSIZE);
/********************************************************** Build node 3 */


HAL_MMC_FillNodeConfig(&MMC_N3, &(Buffer_Tx[BufferWordsSize * 3]), 3 * BLOCKSIZE);

/************************************************** HAL Q initialization */
hal_q_t Q_write;
HAL_Q_Init(&Q_write, &HAL_MMC_DescOps);

/********************************************* Connect node 1 to Queue 1 */
HAL_Q_InsertNode(&Q_write, NULL, &MMC_N1);
/********************************************* Connect node 2 to Queue 1 */
HAL_Q_InsertNode(&Q_write, &MMC_N1, &MMC_N2);
/********************************************* Connect node 3 to Queue 1 */
HAL_Q_InsertNode(&Q_write, &MMC_N2, &MMC_N3);

/*  Write steps */
/* Write blocks using DMA transfer with linked list */
if ((MMC_state = HAL_MMC_WriteBlocks_LinkedList(&hmmc_card, 1000, 12, &Q_write)) != HAL_OK)
{
  Error_Handler();
}

/************************************************** Wait for TX complete */
while(mmctransfertx == 0)
{}
/************************************* Wait for the Card Transfer status */
while(HAL_MMC_GetCardState(&hmmc_card) != HAL_MMC_CARD_TRANSFER)
{}


/* Read steps */


HAL_MMC_FillNodeConfig(&MMC_N4, &(Buffer_Rx[0]), 1 * BLOCKSIZE);



HAL_MMC_FillNodeConfig(&MMC_N5, &(Buffer_Rx[BufferWordsSize*2]), 2 * BLOCKSIZE);



HAL_MMC_FillNodeConfig(&MMC_N6, &(Buffer_Rx[BufferWordsSize*3]), 3 * BLOCKSIZE);

/************************************************** HAL Q initialization */
hal_q_t Q_read;
HAL_Q_Init(&Q_read, &HAL_MMC_DescOps);

HAL_Q_InsertNode(&Q_read, NULL, &MMC_N4);
HAL_Q_InsertNode(&Q_read, &MMC_N4, &MMC_N5);
HAL_Q_InsertNode(&Q_read, &MMC_N5, &MMC_N6);

/* Read back written block using DMA linked-list transfer */
if (HAL_MMC_ReadBlocks_LinkedList(&hmmc_card, 1000, 12, &Q_read) != HAL_OK)
{
  Error_Handler();
}
/*********************************************** Wait for RX/TX complete */
while ((mmctransferrx == 0))
{}
/****************************************** Wait for card transfer state */
while(HAL_MMC_GetCardState(&hmmc_card) != HAL_MMC_CARD_TRANSFER)
{}

Use case: HAL MMC card removal/insertion handling

Sequence diagram

Card presence is typically monitored using a dedicated Card Detect (CD) GPIO pin, with EXTI interrupts used to notify the application of insertion or removal events.

HAL1

HAL2

In HAL1, upon card removal (detected via EXTI), if there is any ongoing processes (read/write) the application should stop them (for instance stop transfers with HAL_MMC_Abort() or HAL_MMC_Abort_IT()). Upon insertion, application calls HAL_MMC_InitCard() which first applies default configurations to the SDMMC peripheral, initializes the card, and then applies user configurations stored in init struct passed within the handle hmmc_card.

In HAL2, the application similarly handles EXTI notifications. On removal, it aborts ongoing processes in the same way but also calls HAL_MMC_NotifyCardRemoval() to apply default configurations. On insertion, it calls HAL_MMC_NotifyCardInsertion() to re-apply user configuration provided within user_config parameter.

@startuml
hide footbox
participant "User Application" as app
participant "HAL MMC" as hal
participant "NVIC" as nvic
activate app

group Normal operation
alt Card is Present
   app -> hal : Periodic operation (read/write)
end
deactivate app
end

nvic -> app : EXTI IRQ (CD removed/inserted)
activate app
group Hot-Plug Check
    app -> app : Read CD Pin

    alt   Card has been removed
          app -> app : Update Card presence Status: DISCONNECTED
          app -> hal : Stop ongoing MMC processes

    else  Card has been inserted
          app -> hal : HAL_MMC_InitCard()
          activate hal
          hal --> app
          deactivate hal
          app -> app : Update Card presence Status: CONNECTED
    end
deactivate app
end
@enduml

Code Snippet

HAL1

HAL2

volatile uint8_t card_present = 0;

/* Example guarded I/O */
void USER_MMC_Application_routine()
{
  if (card_present)
  {
  /* Perform read/write only if card is present */
  /* ... */
  }
}

/* EXTI callback hooked to the MMC card-detect GPIO pin */
void USER_MMC_HotPlugCallback()
{
  if (USER_MMC_READ_DETECT_PIN())
  {
    /* Card removed */
    card_present = 0U;
    /* Abort ongoing processes*/
    User_MMC_StopOngoingProcess(&hmmc_card);


  }
  else
  {
    /* Card inserted */
    HAL_MMC_InitCard(&hmmc_card);
    card_present = 1U;
  }
}
volatile uint8_t card_present = 0;

/* Example guarded I/O */
void USER_MMC_Application_routine()
{
  if (card_present)
  {
  /* Perform read/write only if card is present */
  /* ... */
  }
}

/* EXTI callback hooked to the MMC card-detect GPIO pin */
void USER_MMC_HotPlugCallback()
{
  if (USER_MMC_READ_DETECT_PIN())
  {
    /* Card removed */
    card_present = 0U;
    /* Abort ongoing processes*/
    USER_MMC_StopOngoingProcess(&hmmc_card);

    HAL_MMC_NotifyCardRemoval(&hmmc_card);
  }
  else
  {
    /* Card inserted */
    HAL_MMC_NotifyCardInsertion(&hmmc_card, &user_config);
    card_present = 1U;
  }
}